using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Xml;

namespace Dida
{
	public class StateMachineTemplate<BackendTrait>
		where BackendTrait : StateGlueTrait
	{
		Dictionary<string,StateTemplate<BackendTrait>> states = 
			new Dictionary<string,StateTemplate<BackendTrait>>();
		SettingsContainer[] settingsContainers;

		#region Code the StateMachineDOM uses to build this class

		internal StateMachineTemplate() { }

		internal void SetSettingsContainers(SettingsContainer[] settingsContainers)
		{
			this.settingsContainers = settingsContainers;
		}

		internal void AddTemplate(string name, StateTemplate<BackendTrait> stateTemplate)
		{
			Debug.Assert(!states.ContainsKey(name), "There's already a state called \"" + name + "\"");

			states[name] = stateTemplate;
			stateTemplate.SetStateMachine(this);
		}

		#endregion

		internal SettingsContainer GetSettingsContainer(int index)
		{
			return settingsContainers[index];
		}

		public static StateMachineTemplate<BackendTrait> LoadFromXml(string xmlFileName)
		{
			XmlReaderSettings settings = new XmlReaderSettings();
			settings.IgnoreComments = true;
			settings.IgnoreWhitespace = true;
			using (XmlReader reader = XmlReader.Create(xmlFileName, settings))
			{
				return LoadFromXml(reader);
			}
		}

		public static StateMachineTemplate<BackendTrait> LoadFromXml(XmlReader reader)
		{
			Debug.Assert(reader.Settings.IgnoreComments, "The IgnoreComments setting of the XmlReader must be set to true");
			Debug.Assert(reader.Settings.IgnoreWhitespace, "The IgnoreWhitespace setting of the XmlReader must be set to true");

			throw new NotImplementedException();
			/*StateMachineLoader<BackendTrait> loader =
				new StateMachineLoader<BackendTrait>(reader);
			return loader.Template;*/
		}

		public StateMachine<BackendTrait> CreateInstance()
		{
			StateMachine<BackendTrait> ret = new StateMachine<BackendTrait>(this);
			return ret;
		}

		public State<BackendTrait> CreateStateInstance(string name, 
			StateMachine<BackendTrait> stateMachineInstance)
		{
			return states[name].CreateInstance(stateMachineInstance);
		}
	}

	internal class StateTemplate<BackendTrait>
		where BackendTrait : StateGlueTrait
	{
		StateMachineTemplate<BackendTrait> stateMachine;
		TraitClass traitClass;

		internal struct SettingsContainerInfo
		{
			public int traitIndex;
			public MemberInfo member;
			public int containerIndex;
		}
		SettingsContainerInfo[] settings;

		#region Code the StateMachineLoader uses to build this class

		internal StateTemplate(TraitClass traitClass)
		{
			this.traitClass = traitClass;
		}

		internal void SetSettings(List<SettingsContainerInfo> settingsSrc)
		{
			settings = new SettingsContainerInfo[settingsSrc.Count];
			settingsSrc.CopyTo(settings);
		}

		internal void SetStateMachine(StateMachineTemplate<BackendTrait> stateMachine)
		{
			this.stateMachine = stateMachine;
		}

		#endregion

		public State<BackendTrait> CreateInstance(IStateMachine<BackendTrait> stateMachineInstance)
		{
			TraitInstance traitInstance = traitClass.CreateInstance();

			// set the settings, according to the information
			// in the settings list.
			foreach (SettingsContainerInfo curSettings in settings)
			{
				SettingsContainer settingsContainer = stateMachine.
					GetSettingsContainer(curSettings.containerIndex);

				Trait trait = traitInstance.GetTrait(curSettings.traitIndex);
				if (curSettings.member is PropertyInfo)
				{
					((PropertyInfo)curSettings.member).SetValue(trait,
						settingsContainer, null);
				}
				else
				{
					((FieldInfo)curSettings.member).SetValue(trait,
						settingsContainer);
				}
			}

			return new State<BackendTrait>(traitInstance, stateMachineInstance);
		}
	}
}
